# -*- coding: utf-8 -*-
"""
事件发件箱仓库
"""
from __future__ import annotations

import hashlib
import json
from typing import List, Dict, Any

from common.database import DatabaseManager

# 全局变量用于存储OutboxRelay实例
_outbox_relay_instance = None

def set_outbox_relay_instance(instance):
	"""设置OutboxRelay实例"""
	global _outbox_relay_instance
	_outbox_relay_instance = instance

def get_outbox_relay_instance():
	"""获取OutboxRelay实例"""
	return _outbox_relay_instance


class OutboxRepository:
	def __init__(self, db: DatabaseManager):
		self.db = db

	def save(self, event_type: str, payload: Dict[str, Any], alarm_id: int | None = None, msg_id: str | None = None,
			 meter_code: str | None = None) -> int:
		# **关键修复：与RedisRelay完全一致的指纹计算**
		fingerprint_data = {
			"event_type": event_type,  # 关键：事件类型必须参与去重计算
			"alarm_id": alarm_id,  # 核心：告警ID
			"meter_code": meter_code,  # 核心：设备编码
			"alarm_type": payload.get('alarm_type'),  # 核心：告警类型
			# 移除event_source，确保与RedisRelay指纹计算完全一致
		}
		fingerprint = hashlib.md5(
			json.dumps(fingerprint_data, sort_keys=True).encode()
		).hexdigest()

		# 增强日志记录，特别关注非法开箱告警
		alarm_type = payload.get('alarm_type', 'UNKNOWN')
		from common.logger import create_logger
		logger = create_logger("outbox_repo")
		logger.info(f"[OutboxSave] 保存事件: {event_type}, alarm_type: {alarm_type}, alarm_id: {alarm_id}, meter_code: {meter_code}")
		logger.debug(f"[OutboxSave] Fingerprint: {fingerprint}")

		sql = """
            INSERT INTO am_outbox(event_type, payload_json, fingerprint, alarm_id, msg_id, meter_code)
            VALUES (%s,%s,%s,%s,%s,%s)
            ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id)
        """
		try:
			# **关键修复：依赖外层事务管理，不强制提交**
			self.db.execute_query(
				sql,
				(event_type, json.dumps(payload), fingerprint, alarm_id, msg_id, meter_code),
				commit=False,  # 修改：不强制提交，依赖外层事务
			)
			event_id = self.db.last_insert_id()
			logger.info(f"[OutboxSave] 事件已保存 event_id: {event_id}")

			# 保存后通知OutboxRelay
			relay_instance = get_outbox_relay_instance()
			if relay_instance:
				relay_instance.notify_new_event()
				logger.debug(f"[OutboxSave] 已通知OutboxRelay线程")
			else:
				logger.warning(f"[OutboxSave] OutboxRelay实例不存在，无法通知")

			return event_id

		except Exception as e:
			logger.error(f"[OutboxSave] 保存失败: {e}", exc_info=True)
			raise

	def poll_unprocessed(self, limit: int = 100) -> List[Dict[str, Any]]:
		"""
		查询未处理的事件

		注意：使用独立的数据库连接，不会干扰主线程事务
		"""
		from common.logger import create_logger
		logger = create_logger("outbox_repo")

		# 关键修复：强制启动并立即提交一个新事务，刷新读视图
		# MySQL在REPEATABLE-READ隔离级别下，新事务会看到所有已提交的数据
		if self.db.is_connected():
			try:
				# 使用SQL直接启动并提交事务
				self.db.execute_query("START TRANSACTION", commit=False)
				self.db.execute_query("COMMIT", commit=False)
				logger.debug("[OutboxRepo] 已刷新事务快照")
			except Exception as e:
				logger.warning(f"[OutboxRepo] 刷新事务快照失败: {e}")

		sql = """
			SELECT id, event_type, payload_json, fingerprint, alarm_id, msg_id, meter_code
			FROM am_outbox
			WHERE processed=0
			ORDER BY id ASC
			LIMIT %s
		"""

		result = self.db.execute_query(sql, (limit,), commit=False)
		if result and isinstance(result, list) and len(result) > 0:
			logger.debug(f"[OutboxRepo] 查询未处理事件: 返回 {len(result)} 条")
			return result
		return []

	def mark_processed(self, pk: int) -> None:
		self.db.execute_query(
			"UPDATE am_outbox SET processed=1, processed_at=NOW() WHERE id=%s",
			(pk,),
			commit=False,
		)
